package com.acme.annotation;

/**
 * @author Alexander Kotov (kotov.alex.22@gmail.com)
 */

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TransactionManager implements java.lang.reflect.InvocationHandler {

    private Object obj;

    public static Object applyTransactionDemarcation(final Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
                .getClassLoader(), obj.getClass().getInterfaces(),
                new TransactionManager(obj));
    }

    private TransactionManager(final Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(final Object proxy, final Method m, final Object[] args)
            throws Throwable {

        Object result;
        Transactional transactional = null;

        try {
            Method method = obj.getClass().getMethod(m.getName(), m.getParameterTypes());

            transactional = method.getAnnotation(Transactional.class);
            if (transactional != null) {
                System.out.println("Transaction started");
            }

            result = method.invoke(obj, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }
        if (transactional != null) {
            System.out.println("Transaction comitted");
        }
        return result;
    }
}

